package boxync;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import org.apache.commons.io.FileUtils;

public class BoxyncDir extends FileInfo {
    /**
     * BoxyncDir yg ada di dalam BoxyncDir ini
     */
    ArrayList<BoxyncDir> dirs;
    
    /**
     * File yg ada di dalam direktori ini
     */
    ArrayList<BoxyncFile> files;
    
    public BoxyncDir(BoxyncDir _parent, String _path) {
        file = _path;    
        File f = new File(file);
        
        if (_parent != null) {
            name = f.getName();
            if (!_parent.name.equals(""))
                parent = _parent.getFileName();
            else
                parent = "";
        } else {
            name = "";
            parent = "";
        }
        
        deleted = 0;
        
        files = new ArrayList<BoxyncFile>();
        dirs = new ArrayList<BoxyncDir>();
        
        timeStamp = new Date(f.lastModified());
        timeStamp.setYear(timeStamp.getYear() + 1900);
        
        assignFileInfos();
    }
    
    /**
     * Meng-crawl ulang direktori di harddisk
     */
    public final void assignFileInfos() {
        File d = new File(file);
        d.mkdirs();
        
        dirs.clear();
        files.clear();
        for (File f : d.listFiles()) {
            if (f.isHidden())
                continue;
            
            if (f.isDirectory()) {
                BoxyncDir newD = new BoxyncDir(this, f.getAbsolutePath());
                dirs.add(newD);
            } else {
                BoxyncFile fi = new BoxyncFile(this, f.getAbsolutePath());
                if (!fi.getFileName().equals("/__deleted.txt"))
                    files.add(fi);
            }
        }
    }
    
    /**
     * Mencari BoxyncDir dari String nama direktori
     * @param _dir Path BoxyncDir di dalam working dir
     * @return BoxyncDir
     */
    public BoxyncDir getDirectory(String _dir) {
        BoxyncDir temp = this;
        boolean exist = false;
        if (_dir.equals(""))
            _dir = "/";
        
        while (!temp.getFileName().equals(_dir)) {
            exist = false;
            for (BoxyncDir d : temp.dirs) {
                if (_dir.indexOf(d.getFileName()) != -1) {
                    temp = d;
                    exist = true;
                    break;
                }
            }
            if (!exist)
                return null;
        }
        
        return temp;
    }
    
    public BoxyncDir getFileDirectory(String _file) {
        String _dir = FileInfo.getParent(_file);
        BoxyncDir temp = this;
        boolean exist;
        if (_dir.equals(""))
            _dir = "/";
        
        while (!temp.getFileName().equals(_dir)) {
            exist = false;
            for (BoxyncDir d : temp.dirs) {
                if (_dir.indexOf(d.getFileName()) != -1) {
                    temp = d;
                    exist = true;
                    break;
                }
            }
            if (!exist)
                return null;
        }
        
        return temp;
    }
    
    /**
     * Melist BoxyncFile yg ada di dalam BoxyncDir (rekursif)
     * @return ArrayList<FileInfo> yg ada di BoxyncDir
     */
    public ArrayList<FileInfo> getFileList() {
        ArrayList<FileInfo> afi = new ArrayList<FileInfo>();
        
        afi.add(this);
        afi.addAll(files);
        for (BoxyncDir d : dirs)
            afi.addAll(d.getFileList());
        
        return afi;
    }
    
    public ArrayList<FileInfo> getDeletedList() {
        ArrayList<FileInfo> afi = new ArrayList<FileInfo>();
        
        if (deleted == 1) {
            afi.add(this);
        }
        for (BoxyncFile f : files) {
            if (f.deleted == 1) {
                afi.add(f);
            }
        }
        
        for (BoxyncDir d : dirs) {
            afi.addAll(d.getDeletedList());
        }
        
        return afi;
    }
    
    /**
     * 
     * @return 
     */
    public ArrayList<BoxyncDir> getDeletedDirs() {
        ArrayList<BoxyncDir> del = new ArrayList<BoxyncDir>();
        
        for (BoxyncDir d : dirs) {
            if (d.deleted == 1)
                del.add(d);
            else {
                del.addAll(d.getDeletedDirs());
            }
        }
        
        return del;
    }
    
    /**
     * Melist BoxyncFile yg sudah dimark delete
     * @return 
     */
    public ArrayList<BoxyncFile> getDeletedFiles() {
        ArrayList<BoxyncFile> del = new ArrayList<BoxyncFile>();
        
        if (deleted == 1)
            return del;
        
        for (BoxyncDir d : dirs) {
            del.addAll(d.getDeletedFiles());
        }
        
        for (BoxyncFile fi : files) {
            if (fi.deleted == 1) {
                del.add(fi);
            }
        }
        
        return del;
    }
    
    /**
     * Menyisipkan FileInfo ke direktori yg sesuai.
     * @param fi FileInfo yg ingin disisipkan
     */
    public void insertFile(FileInfo fi) {
        FileInfo fin = searchFile(fi.getFileName());
        
        if (fin != null)
            return;
        
        BoxyncDir temp = getDirectory(fi.parent);
        if (temp == null) {
            (new File(file + fi.file)).mkdirs();
            temp = getDirectory(fi.parent);
        }
        
        if (fi instanceof BoxyncFile)
            temp.files.add((BoxyncFile)fi);
        else if (fi instanceof BoxyncDir)
            temp.dirs.add((BoxyncDir)fi);
    }
    
    /**
     * Menyisipkan file di path ke direktori yg sesuai.
     * @param update String FileInfo dari pull update
     * @param path String path asli FileInfo
     */
    public void insertFile(String update, String path) {
        FileInfo fi = searchFile(FileInfo.getFileName(update));
        
        if (fi != null)
            return;
        
        BoxyncDir temp = getFileDirectory(update);
        File f = new File(path);
        if (temp == null) {
            (new File(file + FileInfo.getParent(update))).mkdirs();
            temp = getFileDirectory(update);
        }

        if (f.isDirectory()) {
            temp.dirs.add(new BoxyncDir(temp, path));
        } else {
            temp.files.add(new BoxyncFile(temp, path));
        }
    }
    
    /**
     * Mencari FileInfo fileName di dalam BoxyncDir.
     * @param fileName Nama file yg ingin dicari
     * @return FileInfo yg dicari jika file ditemukan atau null
     */
    public FileInfo searchFile(String fileName) {
        if (getFileName().equals(fileName))
            return this;
        
        for (BoxyncFile fi : files) {
            if (fi.getFileName().equals(fileName))
                return fi;
        }
        
        FileInfo fi = null;
        for (BoxyncDir dirx : dirs) {
            if ((fi = dirx.searchFile(fileName)) != null)
                return fi;
        }
        return null;
    }
    
    @Override
    public void delete() {
        deleted = 1;
        
        for (BoxyncFile bf : files) {
            bf.delete();
        }
        
        for (BoxyncDir bd : dirs) {
            bd.delete();
        }
        
        new File(file).delete();
    }
    
//    /**
//     * Menghapus FileInfo tertentu dalam direktori.
//     * @param fileInfo FileInfo yg ingin dihapus, dapat berupa direktori atau file
//     */
//    public void deleteFile(String fileInfo) {
//        FileInfo fi = searchFile(fileInfo);
//        
//        fi.deleted = 1;
//        if (fi instanceof BoxyncDir) {
//            ArrayList<FileInfo> listFI = ((BoxyncDir)fi).getFileList();
//            for (FileInfo chfi : listFI) {
//                chfi.deleted = 1;
//            }
//        }
//    }
    
    public void deleteDir() {
        
    }
    
    /**
     * 
     * @return String yg akan dikirim sebagai update. Jika deleted, maka hanya berisi
     * satu baris String yg merupakan BoxyncDir ini. Jika tidak deleted, berisi toString dari
     * BoxyncDir-BoxyncDir dan BoxyncFile-BoxyncFile di dalamnya.
     */
    @Override
    public String toString() {
        if (deleted == 1) {
            if (name.equals(""))
                return "";
            
            return getFileName() + "#" + timeStampString() + "#" + deleted + "\n";
        }
        
        StringBuilder sb = new StringBuilder();
        if (!name.equals("")) {
            String s = getFileName() + "#" + timeStampString() + "#" + deleted + "\n";
            sb.append(s);
        }
        
        for (BoxyncFile fi : files)
            sb.append(fi.toString()).append("\n");
        
        for (BoxyncDir d : dirs)
            sb.append(d.toString());
        
        String s = sb.toString();
        if (name.equals("") && !s.isEmpty()) {
            s = s.substring(0, s.length()-1);
        }
        return s;
    }
    
    public String updateString() {
        if (deleted == 1) {
            if (name.equals(""))
                return "";
            
            return getFileName() + "#" + timeStampString() + "#" + deleted + "\n";
        }
        
        StringBuilder sb = new StringBuilder();
        
        for (BoxyncFile fi : files)
            sb.append(fi.toString()).append("\n");
        
        for (BoxyncDir d : dirs)
            sb.append(d.updateString());
        
        String s = sb.toString();
        if (name.equals("") && !s.isEmpty()) {
            s = s.substring(0, s.length()-1);
        }
        return s;
    }
    
    /**
     * 
     * @return String list BoxyncFile yg akan dikirim ke Client
     */
    public String fullString() {
        StringBuilder sb = new StringBuilder("Directory: ");
        sb.append(parent).append("/").append(name).append("\n");
        
        for (BoxyncFile fi : files)
            sb.append(fi.toString());
        
        sb.append("\n");
        for (BoxyncDir d : dirs)
            sb.append(d.toString());
        
        return sb.toString();
    }
    
    public String delString() {
        if (deleted == 1) {
            if (parent.equals(""))
                return "/" + name + "#" + timeStampString() + "#" + deleted;
            
            return parent + "/" + name + "#" + timeStampString() + "#" + deleted + "\n";
        }
        
        StringBuilder sb = new StringBuilder();
        
        for (BoxyncFile fi : files)
            if (fi.deleted == 1)
                sb.append(fi.toString()).append("\n");
        
        for (BoxyncDir d : dirs)
            sb.append(d.delString());
        
        String s = sb.toString();
        if (parent.equals("") && (!s.isEmpty()))
            s = s.substring(0, s.length()-1);
        return s;
    }
    
    public void move(String dest) {
        File fdest = new File(dest);
        File current = new File(file);
        try {
            FileUtils.moveDirectoryToDirectory(current, fdest, true);
        } catch (IOException e) {
            System.err.println("IOExc in BoxyncDir.move()");
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        BoxyncDir dir = new BoxyncDir(null, "D:/src");
        BoxyncFile f = new BoxyncFile(dir, "D:/src/tes.txt");
        System.out.println(f.timeStamp.getYear());
    }
}
